package application;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;

import jeopardy.common.Utils;
import jeopardy.common.protocol.game.*;
import jeopardy.common.protocol.game.play.AnswerMsg;
import jeopardy.common.protocol.game.play.CurrentUsersMsg;
import jeopardy.common.protocol.game.play.GameRecordMsg;
import jeopardy.common.protocol.game.play.NewQuestionMsg;
import jeopardy.common.protocol.game.play.NotifyStartMsg;
import jeopardy.common.protocol.game.play.QnAAttemptedMsg;
import jeopardy.common.protocol.game.play.QuestionAnswerMsg;
import jeopardy.common.protocol.useraccount.UserAccountConsts;
import jeopardy.common.protocol.useraccount.UserAccountRequest;
import jeopardy.common.protocol.useraccount.UserAccountUtils;


public class LoginScreenLogic {
	
	private static int authenticated;
	private static int connected;
	private static String passWord;
	private static char[] userName;
	String SERVER_IP; 
	static int SERVER_PORT;
	private static SSLSocket authSocket;
	public static byte[] returnCode;
	static UserSession sessionX;
	

	public static int getPreGameGameList(String userName, String passWord) throws Exception, UnknownHostException, IOException
	{
		/* TODO
		 * Create socket to stats port
		 * Write to the port common.jeopardy.common.protocol.game.stats
		 * ShowGameListReqMsg glr = new ShowGameListRequest(userName, passWord) password must be char array
		 * Write to socket - 
		 *     ObjectOutputStream out = new ObjectOutputStream(stat_socket.getOutputStream);
		 * Read from socket - 
		 *     ObjectInputStream in = new ObjectInputStream(stat_sock.getInputStream);
		 *     ShowGameListResMsg = (ShowGameListResMsg) in.readobject()
		 *     
		 *     // ShowGameListResMsg - contains 2 arrays(of game waiting, game playing)
		 *     
		 */
		
		return 0;
	
	}
		
	public static int authenticateUser(String userName, char[] passWord) throws Exception, UnknownHostException, IOException
	{
		/* 
		 * Try to connect to the server - on success attempt to 
		   authenticate the user, otherwise display message
		*/
		if(authSocket.isConnected()) {
			System.out.println("Communication with server established - authenticating");

			
			UserAccountRequest uar = UserAccountUtils
					.createUserAuthRequest(userName, passWord);
			
			System.out.println("User name to send is: "+userName);
			System.out.println("Password to send is: "+ new String(passWord));
			
			if ( writeCommSocket(uar) == 0) {
				// Read the response from the server and then parse it
				Utils.readBytes(authSocket.getInputStream(), returnCode);
				System.out.println("The return code is: "+ returnCode[0]);
				
				// Check the return code for authentication
				if(UserAccountUtils.parseUserAccountResponse(returnCode) ==  ClientConsts.authSuccess) {
					System.out.println("Authentication successful");
					authenticated = 1;
					sessionX.logIn(userName, passWord);
				}
				
				// If authentication failed, print error statement and set authenticated to 0
				if(UserAccountUtils.parseUserAccountResponse(returnCode) ==  ClientConsts.authFailed) {
					System.out.println("getPreGameGameList::authenticateUser - Authentication failure");
					authenticated = 0;
				}

			}
			else {
				System.out.println("Failed to deliver auth infor to server");
				authenticated = 0;
			}
			

		}
		else {
			System.out.println("Couldn't communicate with server");
			authenticated = 0;
		}

		return authenticated;	
	}
	
	/*
	 * This method is used to create socket to communicate with the server
	 */
	public static int createSocket(int type)
	{
		// byte[] returnCode = new byte[UserAccountConsts.USERACCOUNT_MAX_RES_LEN];
		switch(type) {
			
			case 1: SERVER_PORT = ClientConsts.SERVER_PORT_USER_ACCOUNT;
					break;
			case 2: SERVER_PORT = ClientConsts.SERVER_PORT_STATS;
					break;
			case 3: SERVER_PORT = ClientConsts.SERVER_PORT_GAME;
					break;
			default: SERVER_PORT = -9000;
					break;
		}
		try {
			SSLSocketFactory sslsocketfactory = ClientConsts.createSSLFactory();
			authSocket = (SSLSocket) sslsocketfactory.createSocket(
						ClientConsts.SERVER_IP, SERVER_PORT);
			connected = 1;
			return 0;
			
		} catch (Exception exception) {
			exception.printStackTrace();
			System.out.println("Failed to create socket");
			connected = 0;
	        return 1;
		}	
	}

	/*
	 * This method is used to read information from the socket
	 */
	public static int readCommSocket( )
	{
		return 0;
		
	}
	/*
	 * This method is used to send information to the server
	 */
	public static int writeCommSocket(UserAccountRequest uar)
	{
		// byte[] returnCode = new byte[UserAccountConsts.USERACCOUNT_MAX_RES_LEN];
		try {
			authSocket.getOutputStream().write(
					UserAccountUtils.reqToNetworkMsg(uar));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		try {
			authSocket.getOutputStream().flush();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return 0;
	}	

	
	/* 
	 * This is the default constructor that will
	 * handle setting variables and instantiating objects
	 */
	public LoginScreenLogic(){
		authenticated = 0;
		connected = 0;
		passWord = null;
		userName = null;
		authSocket = null;
		String SERVER_IP = null;
		SERVER_PORT = -1;
		returnCode = new byte[UserAccountConsts.USERACCOUNT_MAX_RES_LEN];
		sessionX = UserSession.getInstance();
	}
	

	public String getUserName(){
		return sessionX.getUserName();
	}
	
	public char[] passWord(){
		return sessionX.getPassword();
	}
	
	public static int closeSocket()
	{
		int ret = 0;
		try {
			authSocket.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		if(authSocket.isClosed()) {
			ret = 1;
		}
		
		return ret;
	}
}
